//=============================================================================

#include "../../../../inc/aSystem.h"

//=============================================================================

aSystem::aSystem() : debug_cameraSpeed(0.25f)
{
  glRc = 0;
  hDc = 0;
  hWnd = 0;
  width = 640;
  height = 480;
  fov = 45.0;
  aspect = GLdouble(width)/GLdouble(height);
  nearClip = 0.1;
  farClip = 1000.0;
  clearField = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
  eyes.acSetCamera(aVector(13.0f , 10.0f, 13.0f), aVector(0.0f, 0.0f, 0.0f), aVector(0.0f, 1.0f, 0.0f));
  framesInterval = 0.0f;
  motionSpeed = 1;
  fps = 0;
}

//=============================================================================

bool aSystem::asOpenGLInit()
{
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_POINT_SMOOTH);
  glEnable(GL_POLYGON_OFFSET_FILL);

  glEnableClientState(GL_VERTEX_ARRAY);
  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  glEnableClientState(GL_NORMAL_ARRAY);

  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  glClearDepth(1.0f);
  glPolygonOffset(1.0, 0.5);
  glDepthFunc(GL_LESS);
  glShadeModel(GL_SMOOTH);
  SetCursorPos(width/2, height/2);
  //ShowCursor(FALSE);
  asResizeOpenGL(width, height);

  return 1;
}

//=============================================================================

void aSystem::asResizeOpenGL(GLsizei w, GLsizei h)
{
  if (w <= 0)
    w = 1;

  if (h <= 0)
    h = 1;

  width = w;
  height = h;
  aspect = GLdouble(w)/GLdouble(h);

  glViewport(0, 0, width, height);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(fov, aspect, nearClip, farClip);
  glMatrixMode(GL_MODELVIEW);
}

//=============================================================================

void aSystem::asPaintTheWorld()
{
  glClear(clearField);
  glLoadIdentity();
  eyes.acLookAt();

  //Draw objects and world here
  glDisable(GL_TEXTURE_2D);
  glBegin(GL_LINES);
    glColor3ub(255, 0, 0);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glVertex3f(1.0f, 0.0f, 0.0f);

    glColor3ub(0, 255, 0);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glVertex3f(0.0f, 1.0f, 0.0f);

    glColor3ub(0, 0, 255);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glVertex3f(0.0f, 0.0f, 1.0f);
  glEnd();
  glEnable(GL_TEXTURE_2D);

  asGetFPS();
}

//=============================================================================

void aSystem::asSetDisplayToFullscreen()
{
  DEVMODE dm;

  memset(&dm, 0, sizeof(DEVMODE));
  dm.dmPelsWidth = width;
  dm.dmPelsHeight = height;
  dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
  dm.dmSize = sizeof(DEVMODE);
  ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
}

//=============================================================================

void aSystem::asPrintLastError()const
{
  LPVOID lpMsgBuf;
  
  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL, GetLastError(),
                0, (LPTSTR) &lpMsgBuf,
                0, NULL);
  MessageBox(0, (LPCTSTR)lpMsgBuf, L"Error", MB_OK | MB_ICONERROR);
  LocalFree(lpMsgBuf);
}

//=============================================================================

void aSystem::asKeyDown(WPARAM wp)
{
  switch(useProfile.apGetAction(wp))
  {
    case KA_PUSH:
    {
      aVector f, n;
      aActionPush ap;

      asGetLineUnderMouse(n, f);
      ap.n = n;
      ap.f = f;
      ap.from = eyes.acGetPos();
      WORLD.awReceiveAction(ap);

      break;
    }
    case KA_CANCEL:
    {
      PostQuitMessage(0);

      break;
    }
    case KA_STRAFELEFT:
    {
      eyes.acStrafeCamera(-debug_cameraSpeed);

      break;
    }
    case KA_STRAFERIGHT:
    {
      eyes.acStrafeCamera(debug_cameraSpeed);

      break;
    }
    case KA_MOVEFORWARD:
    {
      eyes.acMoveCamera(debug_cameraSpeed);

      break;
    }
    case KA_MOVEBACKWARD:
    {
      eyes.acMoveCamera(-debug_cameraSpeed);

      break;
    }
    case KA_JUMP:
    {
      eyes.acMoveUp(debug_cameraSpeed);

      break;
    }
    case KA_CROUCH:
    {
      eyes.acMoveUp(-debug_cameraSpeed);

      break;
    }
    default:
    {
      break;
    }
  }
}

//=============================================================================

void aSystem::asCalculateFPS()
{
  static float frameTime = 0.0f;
  static float lastTime = 0.0f;
  float currentTime = GetTickCount()/1000.0f;

  framesInterval = currentTime - frameTime;
  if (AUX.aaCompareFloat(frameTime, 0.0f))
    AUX.dt = 0.0f;
  else
    AUX.dt = framesInterval/motionSpeed;

  frameTime = currentTime;
  ++fps;
  
  if ((currentTime - lastTime) > 1.0f)
  {
    lastTime = currentTime;
    fps = 0;
  }
}

//=============================================================================

void aSystem::asParseParameters(const aString& str)
{
  aList<aString> list;

  str.asGetWords(list);

  aItem<aString>* tmpItem = list.alGetFirstItem();

  while(tmpItem)
  {
    if (tmpItem->data == "/log")
      LOG.logon = 1;

    tmpItem = tmpItem->next;
  }
}

//=============================================================================

void aSystem::asGetLineUnderMouse(aVector& n, aVector& f)
{
  float x, y;
  GLint viewPort[4];
  GLdouble projection[16];
  GLdouble modelView[16];
  GLdouble wx, wy, wz;
  POINT mp;
  
  GetCursorPos(&mp);
  glGetIntegerv(GL_VIEWPORT, viewPort);
  glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
  glGetDoublev(GL_PROJECTION_MATRIX, projection);
  x = (float)mp.x;
  y = (float)(asGetHeight() - mp.y);
  gluUnProject(x, y, -1.0, modelView, projection, viewPort, &wx, &wy, &wz);
  n.x = float(wx);
  n.y = float(wy);
  n.z = float(wz);
  gluUnProject(x, y, 1.0, modelView, projection, viewPort, &wx, &wy, &wz);
  f.x = float(wx);
  f.y = float(wy);
  f.z = float(wz);
}

//=============================================================================

aSystem::~aSystem()
{
}

//=============================================================================
